using System.Collections.Generic;
using GeneticAlgorithms.Genomes;

namespace GeneticAlgorithms.Populations
{
    /// <summary>
    /// Base interface for genetic populations.
    /// </summary>
    /// <remarks>
    /// A population consists of a collection of individual genomes,
    /// each of which representing a possible solution for the problem
    /// the GA is working with.
    /// </remarks>
    public interface IPopulation
    {
        /// <summary>
        /// Gets the number of elapsed generations.
        /// </summary>
        /// <value>The number of elapsed generations.</value>
        int Generations { get; }

        /// <summary>
        /// Gets the average fitness.
        /// </summary>
        /// <value>The average fitness.</value>
        double? AverageFitness { get; }

        /// <summary>
        /// Gets the best fitness among the population's genomes.
        /// </summary>
        /// <value>The best fitness.</value>
        double BestFitness { get; }

        /// <summary>
        /// Gets the genomes variance.
        /// </summary>
        /// <value>The variance.</value>
        double? Variance { get; }

        /// <summary>
        /// Gets the variance from generation to generation.
        /// </summary>
        /// <value>The generation variance.</value>
        double? GenerationVariance { get; }

        /// <summary>
        /// Gets or sets the populationSize of the elite.
        /// </summary>
        /// <value>The populationSize of the elite.</value>
        int EliteSize { get; set; }

        /// <summary>
        /// Initializes the population.
        /// </summary>
        void Initialize();

        /// <summary>
        /// Performs a single evolutionary step.
        /// </summary>
        void DoStep();

        /// <summary>
        /// Sorts all genomes in the population, according to their fitness.
        /// </summary>
        void Sort();

        /// <summary>
        /// Updates the population stats.
        /// </summary>
        void UpdateStats();

        /// <summary>
        /// Gets the best genome in this population.
        /// </summary>
        /// <returns>
        /// The fittest genome in the population.
        /// </returns>
        IGenomeBase GetBest();

        /// <summary>
        /// Gets the genome count in the population.
        /// </summary>
        /// <value>The number of genomes that are currently in the population.</value>
        int Count { get; }
    }

    /// <summary>
    /// Base generic interface for populations.
    /// </summary>
    /// <typeparam name="TGenome">The type of the genome.</typeparam>
    /// <typeparam name="TGene">The type of the gene.</typeparam>
    public interface IPopulation<TGenome, TGene> : IPopulation, IEnumerable<TGenome> 
        where TGenome : IGenome<TGene>
    {
        /// <summary>
        /// Gets the best genome in this population.
        /// </summary>
        /// <returns>
        /// The fittest genome in the population.
        /// </returns>
        new TGenome GetBest();

        /// <summary>
        /// Gets the <see cref="GeneticAlgorithms.Genomes.IGenome&lt;TGene&gt;"/> at the specified index.
        /// </summary>
        /// <value>
        /// The genome located at posiction <param name="index"/>.
        /// </value>
        TGenome this[int index] { get; }
    }
}
